package com.powernode.spring6.service;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.*;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

@Component("logAspect")
@Aspect // 切面是需要@Aspect注解标注的
@Order(2) // @Order控制切面的执行顺序，数字越小，优先级越高
public class LogAspect { // 切面

    // 切面 = 通知 + 切点
    // 通知就是增强，就是具体要编写的增强代码
    // 这里的advice以方法的形式出现

    // 定义通用的切点表达式
    @Pointcut("execution(* com.powernode.spring6.service..*(..))")
    public void 通用切点(){
        // 这个方法只是一个标记，方法名随意，方法体也不需要写任何代码
    }

    // 前置通知
    // @Before注解标注的方法就是前置通知
    @Before("通用切点()")
    public void beforeAdvice(JoinPoint joinPoint){
        System.out.println("前置通知");
        // 这个 JoinPoint joinPoint，在Spring容器调用这个方法的时候自动传过来
        // JoinPoint joinPoint有什么用？

        Signature signature = joinPoint.getSignature(); // 得到目标方法的签名 比如：public void login()
        // 通过方法的签名可以得到目标方法的方法名、返回值类型等
        System.out.println("目标方法的方法名："+signature.getName());
    }

    // 后置通知
    @AfterReturning("通用切点()")
    public void afterReturningAdvice(JoinPoint joinPoint){
        System.out.println("后置通知");
    }

    // 环绕通知（环绕是最大的通知，在前置之前，在后置之后）
    @Around("通用切点()")
    public void aroundAdvice(ProceedingJoinPoint joinPoint) throws Throwable {
        // 前面的代码
        System.out.println("前环绕");
        // 执行目标
        joinPoint.proceed();
        // 后面的通知
        System.out.println("后环绕");
    }

    // 异常通知
    @AfterThrowing("通用切点()")
    public void afterThrowingAdvice(JoinPoint joinPoint){
        System.out.println("异常通知");
    }

    // 最终通知（finally语句块中的通知）
    @After("通用切点()")
    public void afterAdvice(JoinPoint joinPoint){
        System.out.println("最终通知");
    }
}
